#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 游戏参数定义
#define WIDTH 40
#define HEIGHT 20

// 方向定义
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77

// 蛇的节点结构体
typedef struct SnakeNode {
    int x;
    int y;
    struct SnakeNode *next;
} SnakeNode;

// 全局变量
int score = 0;         // 分数
int gameOver = 0;      // 游戏结束标志
int direction = RIGHT; // 初始方向向右
int foodX, foodY;      // 食物位置
SnakeNode *head = NULL; // 蛇头
SnakeNode *tail = NULL; // 蛇尾

// 函数声明
void initGame();
void drawGame();
void gameLogic();
void handleInput();
void createFood();
void addSnakeNode(int x, int y);
void moveSnake();
void checkCollision();
void clearSnake();
void setCursorPosition(int x, int y);
void hideCursor();

// 主函数
int main() {
    // 初始化游戏
    initGame();
    
    // 游戏主循环
    while (!gameOver) {
        drawGame();
        handleInput();
        Sleep(100); // 控制游戏速度
        gameLogic();
    }
    
    // 游戏结束
    setCursorPosition(WIDTH/2 - 5, HEIGHT/2);
    printf("游戏结束!");
    setCursorPosition(WIDTH/2 - 10, HEIGHT/2 + 1);
    printf("最终得分: %d", score);
    setCursorPosition(WIDTH/2 - 15, HEIGHT/2 + 2);
    printf("按任意键退出...");
    
    // 清除资源
    clearSnake();
    _getch();
    
    return 0;
}

// 初始化游戏
void initGame() {
    // 隐藏光标
    hideCursor();
    
    // 初始化随机数种子
    srand(GetTickCount());
    
    // 初始化蛇，从中间位置开始
    int startX = WIDTH / 2;
    int startY = HEIGHT / 2;
    
    // 创建蛇，先添加尾部，再添加头部，确保顺序正确
    addSnakeNode(startX - 2, startY); // 尾部
    addSnakeNode(startX - 1, startY); // 身体
    addSnakeNode(startX, startY);     // 头部
    
    // 创建初始食物
    createFood();
    
    // 初始化分数
    score = 0;
    gameOver = 0;
    direction = RIGHT;
}

// 绘制游戏界面
void drawGame() {
    // 清空屏幕
    system("cls");
    
    // 绘制上边界
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    
    // 绘制游戏区域
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH + 2; j++) {
            // 绘制左右边界
            if (j == 0 || j == WIDTH + 1) {
                printf("#");
            } else {
                // 检查是否是蛇头
                if (head != NULL && j - 1 == head->x && i == head->y) {
                    printf("@");
                } 
                // 检查是否是蛇身
                else {
                    int isSnakeBody = 0;
                    if (head != NULL) { // 确保head不为NULL
                        SnakeNode *current = head->next;
                        while (current != NULL) {
                            if (j - 1 == current->x && i == current->y) {
                                printf("O");
                                isSnakeBody = 1;
                                break;
                            }
                            current = current->next;
                        }
                    }
                    
                    // 检查是否是食物
                    if (!isSnakeBody) {
                        if (j - 1 == foodX && i == foodY) {
                            printf("*");
                        } else {
                            printf(" ");
                        }
                    }
                }
            }
        }
        printf("\n");
    }
    
    // 绘制下边界
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    
    // 显示分数
    printf("得分: %d\n", score);
    printf("使用方向键控制蛇的移动\n");
}

// 处理用户输入
void handleInput() {
    if (_kbhit()) { // 检查是否有按键输入
        int key = _getch();
        
        // 处理方向键
        if (key == 0 || key == 224) { // 方向键的特殊处理
            key = _getch(); // 获取实际的方向键代码
            
            // 根据按键设置方向，防止180度转向
            switch (key) {
                case UP:
                    if (direction != DOWN) direction = UP;
                    break;
                case DOWN:
                    if (direction != UP) direction = DOWN;
                    break;
                case LEFT:
                    if (direction != RIGHT) direction = LEFT;
                    break;
                case RIGHT:
                    if (direction != LEFT) direction = RIGHT;
                    break;
            }
        }
        // 按ESC键退出游戏
        else if (key == 27) {
            gameOver = 1;
        }
    }
}

// 控制游戏逻辑
void gameLogic() {
    moveSnake();
    checkCollision();
}

// 移动蛇
void moveSnake() {
    // 确保head不为NULL
    if (head == NULL) {
        return;
    }
    
    int newX = head->x;
    int newY = head->y;
    
    // 根据方向计算新的头部位置
    switch (direction) {
        case UP:
            newY--;
            break;
        case DOWN:
            newY++;
            break;
        case LEFT:
            newX--;
            break;
        case RIGHT:
            newX++;
            break;
    }
    
    // 添加新的头部
    addSnakeNode(newX, newY);
    
    // 检查是否吃到食物
    if (newX == foodX && newY == foodY) {
        score += 10; // 增加分数
        createFood(); // 创建新食物
        // 吃到食物时不移除尾部，蛇身变长
    } else {
        // 没有吃到食物，移除尾部，保持蛇身长度不变
        if (head != NULL && tail != NULL && head != tail) {
            SnakeNode *temp = tail;
            SnakeNode *prev = head;
            
            // 找到尾部的前一个节点
            while (prev != NULL && prev->next != tail) {
                prev = prev->next;
            }
            
            // 更新尾部指针
            if (prev != NULL) {
                tail = prev;
                tail->next = NULL;
                
                // 释放旧尾部节点
                free(temp);
            }
        }
    }
}

// 检查碰撞
void checkCollision() {
    // 确保head不为NULL
    if (head == NULL) {
        gameOver = 1;
        return;
    }
    
    // 检查是否撞到墙壁
    if (head->x < 0 || head->x >= WIDTH || head->y < 0 || head->y >= HEIGHT) {
        gameOver = 1;
        return;
    }
    
    // 检查是否撞到自己
    SnakeNode *current = head->next;
    while (current != NULL) {
        if (head->x == current->x && head->y == current->y) {
            gameOver = 1;
            return;
        }
        current = current->next;
    }
}

// 创建食物
void createFood() {
    // 生成随机位置，确保不在蛇身上
    int foodOnSnake;
    
    do {
        foodOnSnake = 0;
        foodX = rand() % WIDTH;
        foodY = rand() % HEIGHT;
        
        // 检查食物是否在蛇身上
        SnakeNode *current = head;
        while (current != NULL) {
            if (foodX == current->x && foodY == current->y) {
                foodOnSnake = 1;
                break;
            }
            current = current->next;
        }
    } while (foodOnSnake);
}

// 添加蛇节点
void addSnakeNode(int x, int y) {
    SnakeNode *newNode = (SnakeNode *)malloc(sizeof(SnakeNode));
    newNode->x = x;
    newNode->y = y;
    newNode->next = NULL;
    
    // 如果是空链表，设置头尾
    if (head == NULL) {
        head = newNode;
        tail = newNode;
    } else {
        // 否则添加到头部
        newNode->next = head;
        head = newNode;
    }
}

// 清除蛇，释放内存
void clearSnake() {
    SnakeNode *current = head;
    SnakeNode *next;
    
    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }
    
    head = NULL;
    tail = NULL;
}

// 设置光标位置
void setCursorPosition(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 隐藏光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}